<?php

/*
 *  class conexion a base de datos orm
 *  desarrollado por: ebrain cedeno
 */

abstract class ActiveRecord{
    
    public static $_host;
    public static $_user;
    public static $_pass;
    public static $_dbname;
    public static $_type;
    public static $_port=0;
    
    private $_conexion;
    private $_class_name;
    private $_tables = array();
    private $_columnas = array();
    private $_defaul_value = array();
    private $_primary_key;
    
    //controles para mover de registro
    
    private $_current_key = 0;
    private $_mi_collection;


    public function __construct($classname = __CLASS__) {
        
        $this->_class_name = $classname;
        
        switch (strtolower(self::$_type)){

            case CONNECTION_TYPE::MYSQL:
                
                /* conectando a la base de datos */
                
                try{
                
                    if (self::$_port == 0){
                        self::$_port = 3306;
                    }
                    
                    if (!$this->_conexion = mysql_connect(self::$_host.":".self::$_port,  self::$_user ,self::$_pass)){
                        throw new Exception("Error al intentar conectado a la base de datos ".  mysql_error($this->_conexion));
                    }
                    else{
                        if (!mysql_select_db(self::$_dbname)){
                            throw  new Exception("Error al intentar seleccionar a la base de datos ".mysql_error($this->_conexion));
                        }
                    }
                
                    $tablas_array = $this->GetTables();
                    
                    foreach ($this->GetColumns($tablas_array[array_search($classname, $tablas_array)]) as $llave=>$columnas){
                        $this->$columnas = $this->_defaul_value[$columnas];  
                    }
                    
                    $this->_primary_key = $this->GetPrimaryKey();
                    
                    // cargando los objetos de relacion al crear la tabla
                    
                    $this->GetRelations();
                    
                }catch (Exception $error){
                    throw new Exception($error->getMessage());
                }
                break;
        }
    }
    
    public function GetColumns(){
        $query = mysql_query("SHOW COLUMNS FROM ".$this->_class_name);
        
        while ($resultado = mysql_fetch_assoc($query)){
            $this->_columnas[]=$resultado['Field'];
            $this->_defaul_value[$resultado['Field']] = $resultado['Default'];
        }
        
        return $this->_columnas;
        
    }
    
    public function GetPrimaryKey(){
        try{
            
            $sql = "SHOW INDEXES FROM ".$this->_class_name." WHERE UPPER(Key_name) = 'PRIMARY'";
            $query = mysql_query($sql);
            return mysql_fetch_object($query)->Column_name;
            
        }catch(Exception $error){
            throw new Exception($error->getMessage());
        }
    }
    
    public function GetRelations($table=null){
        
        $esta_table = (is_null($table))?$this->_class_name:$table;
        $sql = "SELECT DISTINCT(REFERENCED_TABLE_NAME) as REFERENCED FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_NAME='".$esta_table."'";
        $query = mysql_query($sql);
        
        while($result = mysql_fetch_assoc($query)){
            if (!is_null($result['REFERENCED'])){
                
                //comenzamos a preparar el objeto para crear los parientes
                
                $this->$result['REFERENCED'] = new stdClass();
                
                //buscaamos los campos de nuestra tabla emparentada y los agregamos aqui
                
                $sql_reference = "SHOW COLUMNS FROM ".$result['REFERENCED'];
                $query_reference = mysql_query($sql_reference);
                
                while ($result_reference = mysql_fetch_assoc($query_reference)){
                    if (!is_null($result_reference['Default'])){
                        $this->$result['REFERENCED']->$result_reference['Field'] = $result_reference['Default'];
                    }
                    else{
                        $this->$result['REFERENCED']->$result_reference['Field'] = "";
                    }
                }        
            }
        }
    }
    
    public function GetTables(){
        
        $query = mysql_query("SHOW TABLES FROM ".self::$_dbname);
        $tables = array();
        while ($resultado = mysql_fetch_assoc($query)){
            $tables[]=$resultado['Tables_in_'.self::$_dbname];
        }
        
        return $tables;
        
    }
    
    public function find(){
        
        $param = func_get_args();
        
        //CALCULANDO LOS WHERE DE LA CONSULTA
       
        if (count($param) == 1 and is_numeric($param[0])){
            $WHERE = " WHERE ".$param[0];
        }
        else if (count($param) == 2 and is_array($param[1]) and is_string($param[0])){
            $WHERE = " WHERE ".$param[0];
            foreach ($param[1] as $key=>$value){
                $WHERE = str_replace($key, "'".$value."'", $WHERE);
            }
        }
        else{
            $WHERE = "";
        }
        
        //CREANDO LA CONSULTA PARA TRAER LOS DATOS
        try{
            $sql = "SELECT * FROM ".$this->_class_name.$WHERE;
            $query = mysql_query($sql,  $this->_conexion);
            $resultado = mysql_fetch_assoc($query);
        
            $tempClass = new $this->_class_name;
            foreach ($resultado as $campo=>$valor){
                $tempClass->$campo = $valor;
            }
            
            //generando los objetos de la relacion
            
            $sql_column_relation = "SELECT DISTINCT(REFERENCED_TABLE_NAME) as REFERENCED,REFERENCED_COLUMN_NAME,COLUMN_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_NAME='".$this->_class_name."'";
            $query_column_relation = mysql_query($sql_column_relation);
            
            while ($result_column_relation = mysql_fetch_assoc($query_column_relation)){
                if (!is_null($result_column_relation['REFERENCED'])){
                    
                    // cargamos elregistro de relacion con su respectiva clase
                    $objeto = new $this($result_column_relation['REFERENCED']);
                    $tempClass->$result_column_relation['REFERENCED'] = $objeto->find($result_column_relation['REFERENCED_COLUMN_NAME']." = :".$result_column_relation['REFERENCED_COLUMN_NAME'],array(":".$result_column_relation['REFERENCED_COLUMN_NAME']=>$tempClass->$result_column_relation['COLUMN_NAME']));
                    
                }
            }

            return $tempClass;
            
        }catch (Exception $error){
            throw new Exception($error->getMessage());
        }
    }
    
    public function findAll($condicion="",$params=array()){
        if (!empty($condicion)){
            if (count($params) > 0){
                $WHERE = " WHERE ".$condicion;
                foreach ($params as $llave=>$value){
                    $WHERE = str_replace($llave,"'".$value."'",$WHERE);
                }
            }
            else{
                $WHERE = "";
            }
        }
        else{
            $WHERE = "";
        }
        
        try{
            
            $sql = "SELECT * FROM ".$this->_class_name.$WHERE;
            
            $query = mysql_query($sql);
            $array_result = array();
            while ($resultado = mysql_fetch_assoc($query)){
                $class_temp = new $this->_class_name;
                foreach ($resultado as $llave=>$valor){
                    $class_temp->$llave = $valor;
                }
                
                //generando los objetos de la relacion
            
            $sql_column_relation = "SELECT DISTINCT(REFERENCED_TABLE_NAME) as REFERENCED,REFERENCED_COLUMN_NAME,COLUMN_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_NAME='".$this->_class_name."'";
            $query_column_relation = mysql_query($sql_column_relation);
            
        
            
            while ($result_column_relation = mysql_fetch_assoc($query_column_relation)){
                if (!is_null($result_column_relation['REFERENCED'])){
                    
                    // cargamos elregistro de relacion con su respectiva clase
                    $objecto = new $this($result_column_relation['REFERENCED']);
                    $class_temp->$result_column_relation['REFERENCED']=$objecto->find($result_column_relation['REFERENCED_COLUMN_NAME']." = :".$result_column_relation['REFERENCED_COLUMN_NAME'],array(":".$result_column_relation['REFERENCED_COLUMN_NAME']=>$class_temp->$result_column_relation['COLUMN_NAME']));
                    unset($objecto);
                }
            }
                
            
                $array_result[]=$class_temp;
                unset($class_temp);
            }
            
            return $array_result;
            
        }catch(Exception $error){
            throw new Exception($error->getMessage());
        }
        
    }
    
    public function findByPk($pk,$condition='',$params=array()){
        try{
            
            if (empty($pk)){
                throw new Exception("Asigne la clave primaria");
            }
            else{
                
                // cargando la condicion del pk
                    
                $WHERE = " WHERE ".$this->_primary_key." ='".$pk."' ";
                
                if (!empty($condition)){
                    
                    if (count($params) > 0){
                        $WHERE .= $condition;
                        foreach($params as $llave=>$valor){
                            $WHERE = str_replace($llave,"'".$valor."'",$WHERE);
                        }
                    }
                }
                
                $sql = "SELECT * FROM ".$this->_class_name.$WHERE;
                $query = mysql_query($sql);
                $tempClass = new $this->_class_name;
                foreach (mysql_fetch_assoc($query) as $key=>$value){
                    $tempClass->$key = $value;
                }
                
                //generando los objetos de la relacion
            
            $sql_column_relation = "SELECT DISTINCT(REFERENCED_TABLE_NAME) as REFERENCED,REFERENCED_COLUMN_NAME,COLUMN_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_NAME='".$this->_class_name."'";
            $query_column_relation = mysql_query($sql_column_relation);
            
            while ($result_column_relation = mysql_fetch_assoc($query_column_relation)){
                if (!is_null($result_column_relation['REFERENCED'])){
                    
                    // cargamos elregistro de relacion con su respectiva clase
                    $objeto = new $this($result_column_relation['REFERENCED']);
                    $tempClass->$result_column_relation['REFERENCED'] = $objeto->find($result_column_relation['REFERENCED_COLUMN_NAME']." = :".$result_column_relation['REFERENCED_COLUMN_NAME'],array(":".$result_column_relation['REFERENCED_COLUMN_NAME']=>$tempClass->$result_column_relation['COLUMN_NAME']));
                    unset($objeto);
                }
            }
                
                return $tempClass;
                
            }
            
        }catch(Exception $error){
            throw new Exception($error->getMessage());
        }
    }
    
    public function findBySql($sql,$param){
        print "falta implementar";
    }
    
    public function save(){
        
        try{
         
            $sql = "INSERT INTO ".$this->_class_name." (";
            $sql_data = " VALUES (";
            
            foreach ($this->_columnas as $llave=>$value){
                if (trim($this->_primary_key) !== $value){
                    $sql .= $value.',';
                    $sql_data .= "'".$this->$value."',";
                }
                
            }
            
            $sql = substr($sql,0,-1).") ";
            $sql_data = substr($sql_data,0,-1).");";
            $sql = $sql.$sql_data;
            
            if (!mysql_query($sql)){
                return false;
            }
            else{
                
                $temp_class = $this->findByPk(mysql_insert_id());
                foreach ($this->_columnas as $key=>$name_property){
                    $this->$name_property = $temp_class->$name_property;
                }
                
            }
            
        }catch(Exception $error){
            throw new Exception($error->getMessage());
        }
    }
    
    public function update(){
        
        try{
            $sql = "UPDATE ".$this->_class_name." ";
            foreach ($this->_columnas as $llave => $field_name){
                if (trim($this->_primary_key) !== trim($field_name)){
                    $sql .= "SET ".$field_name."='".$this->$field_name."',";
                }
            }
            $primary_key_value = $this->_primary_key;
            $sql = substr($sql,0,-1)." WHERE ".$this->_primary_key."='".$this->$primary_key_value."';";
            
            if (!mysql_query($sql)){
                return false;
            }
            else{
                return true;
            }
            
        }catch(Exception $error){
            throw new Exception($error->getMessage());
        }
        
    }
    
    public function deleteAll(){
        try{
            $sql = "DELETE FROM ".$this->_class_name;
            if (!mysql_query($sql)){
                return false;
            }
            else{
                return true;
            }
        }catch(Exception $error){
            throw new Exception($error->getMessage());
        }
    }
    
    public function delete($condition,$param){
        if (!is_array($param)){
            throw new Exception("Condicion no encontrado por favor verifique");
        }
        else{
            if (empty($condition)){
                throw new Exception("Condicion no encontrado por favor verifique");
            }
            
            foreach ($param as $key=>$value_condicion){
                $condition = str_replace($key,$value_condicion,$condition);
            }
            
            $sql = "DELETE FROM ".$this->_class_name." WHERE ".$condition;
            if (mysql_query($sql)){
                return true;
            }
            else{
                return false;
            }
        }
    }
    
    public function Count($condition="",$param=""){
        if (is_array($param)){
            
            foreach ($param as $key=>$value_count){
                $condition = str_replace($key, $value_count, $condition);
            }
            
            $WHERE = " WHERE ".$condition;
        }
        else{
            $WHERE = "";
        }
        
        $sql = "SELECT * FROM ".$this->_class_name.$WHERE;
        $query = mysql_query($sql);
        return mysql_num_rows($query);
    }
    
    public function first(){
        
        $this->_mi_collection = $this->findAll();
        if (count($this->_mi_collection) > 0){
            return $this->_mi_collection[0];
        }
        else{
            return null;
        }
        
    }
    
    public function last(){
        
        //verificamos si ya estan cargados los dato si no los cargamos
        
        if (count($this->_mi_collection) == 0){
            $this->_mi_collection = $this->findAll();
        }
        
        if (count($this->_mi_collection) > 0){
            $this->_current_key = count($this->_mi_collection)-1;
            return $this->_mi_collection[$this->_current_key];
        }
        else{
            
            return null;
        }
    }
    
    public function next(){
        
        if (count($this->_mi_collection) > 0){
            if ($this->_current_key >= 0 and (count($this->_mi_collection)-1) > 0 and $this->_current_key < (count($this->_mi_collection)-1)){
                $this->_current_key++;
                return $this->_mi_collection[$this->_current_key];
            }
            elseif ($this->_current_key >= 0 ){
              
                return $this->_mi_collection[$this->_current_key];
            }
            else{
                return $this->_mi_collection[$this->_current_key];
            }
        }
        else{
            throw new Exception("no se encontro objeto ActiveRecord cargado");
        }
    }
    
    public function back(){
        
        if (count($this->_mi_collection) > 0){
            if ($this->_current_key == (count($this->_mi_collection)-1) and $this->_current_key > 0){
                $this->_current_key--;
                return $this->_mi_collection[$this->_current_key];
            }
            elseif ($this->_current_key != 0 and $this->_current_key < (count($this->_mi_collection)-1)){
              
                return $this->_mi_collection[$this->_current_key];
            }
            else{
                return $this->_mi_collection[$this->_current_key];
            }
        }
        else{
            throw new Exception("no se encontro objeto ActiveRecord cargado");
        }
        
    }
}

class CONNECTION_TYPE{
    
    CONST MYSQL = "mysql";
    CONST POSTGRESQL = "pgsql";
    
}

?>
